using NFreeMarker.Core;
using NUnit.Framework;

// ReSharper disable InconsistentNaming
namespace NFreeMarker.Tests.Template
{
    public class TemplateTests_ProcessArithmeticalOperations
    {
        [TestFixture]
        public class When_processing_an_add_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_two_int_values_can_be_added()
            {
                SetTemplateContent("${numberA + numberB}");
                AddTemplateVariable("numberA", (short) 1);
                AddTemplateVariable("numberB", (short) 2);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("3"));
            }

            [Test]
            public void Assure_two_float_values_can_be_added()
            {
                SetTemplateContent("${numberA + numberB}");
                AddTemplateVariable("numberA", 1.2f);
                AddTemplateVariable("numberB", 3.4f);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("4.6"));
            }

            [Test]
            public void Assure_two_double_values_can_be_added()
            {
                SetTemplateContent("${numberA + numberB}");
                AddTemplateVariable("numberA", 1.2);
                AddTemplateVariable("numberB", 3.4);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("4.6"));
            }

            [Test]
            public void Assure_a_NonStringException_is_thrown_when_trying_to_add_two_booleans()
            {
                SetTemplateContent("${valueA + valueB}");
                AddTemplateVariable("valueA", true);
                AddTemplateVariable("valueB", false);

                Assert.That(
                    () => ProcessTemplate(),
                    Throws.Exception.TypeOf<NonStringException>());
            }
        }

        [TestFixture]
        public class When_processing_a_divide_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_two_int_values_can_be_divided()
            {
                SetTemplateContent("${numberA / numberB}");
                AddTemplateVariable("numberA", 4);
                AddTemplateVariable("numberB", 2);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("2"));
            }

            [Test]
            public void Assure_two_float_values_can_be_divided()
            {
                SetTemplateContent("${numberA / numberB}");
                AddTemplateVariable("numberA", 2.42f);
                AddTemplateVariable("numberB", 1.1f);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("2.2"));
            }

            [Test]
            public void Assure_two_double_values_can_be_multiplied()
            {
                SetTemplateContent("${numberA / numberB}");
                AddTemplateVariable("numberA", 2.42);
                AddTemplateVariable("numberB", 1.1);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("2.2"));
            }

            [Test]
            public void Assure_a_NonStringException_is_thrown_when_the_values_are_booleans()
            {
                SetTemplateContent("${valueA / valueB}");
                AddTemplateVariable("valueA", true);
                AddTemplateVariable("valueB", false);

                Assert.That(
                    () => ProcessTemplate(),
                    Throws.Exception.TypeOf<NonNumericalException>());
            }
        }

        [TestFixture]
        public class When_processing_a_modulus_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_two_int_values_can_be_modulus_calculated()
            {
                SetTemplateContent("${numberA % numberB}");
                AddTemplateVariable("numberA", 5);
                AddTemplateVariable("numberB", 2);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("1"));
            }

            [Test]
            public void Assure_two_float_values_can_be_modulus_calculated()
            {
                SetTemplateContent("${numberA % numberB}");
                AddTemplateVariable("numberA", 3.3f);
                AddTemplateVariable("numberB", 1.1f);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("1.1"));
            }

            [Test]
            public void Assure_two_double_values_can_be_modulus_calcuated()
            {
                SetTemplateContent("${numberA % numberB}");
                AddTemplateVariable("numberA", 3.3);
                AddTemplateVariable("numberB", 1.1);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("1.1"));
            }
        }

        [TestFixture]
        public class When_processing_a_multiply_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_two_int_values_can_be_multiplied()
            {
                SetTemplateContent("${numberA * numberB}");
                AddTemplateVariable("numberA", (short) 2);
                AddTemplateVariable("numberB", (short) 3);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("6"));
            }

            [Test]
            public void Assure_two_float_values_can_be_multiplied()
            {
                SetTemplateContent("${numberA * numberB}");
                AddTemplateVariable("numberA", 1.2f);
                AddTemplateVariable("numberB", 3.4f);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("4.08"));
            }

            [Test]
            public void Assure_two_double_values_can_be_multiplied()
            {
                SetTemplateContent("${numberA * numberB}");
                AddTemplateVariable("numberA", 1.2);
                AddTemplateVariable("numberB", 3.4);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("4.08"));
            }
        }

        [TestFixture]
        public class When_processing_a_subtract_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_two_int_values_can_be_subtracted()
            {
                SetTemplateContent("${numberA - numberB}");
                AddTemplateVariable("numberA", (short) 3);
                AddTemplateVariable("numberB", (short) 1);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("2"));
            }

            [Test]
            public void Assure_two_float_values_can_be_subtracted()
            {
                SetTemplateContent("${numberA - numberB}");
                AddTemplateVariable("numberA", 4.6f);
                AddTemplateVariable("numberB", 1.2f);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("3.4"));
            }

            [Test]
            public void Assure_two_double_values_can_be_subtracted()
            {
                SetTemplateContent("${numberA - numberB}");
                AddTemplateVariable("numberA", 4.6);
                AddTemplateVariable("numberB", 1.2);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("3.4"));
            }
        }

        [TestFixture]
        public class When_processing_a_unary_plus_operation : TemplateTestsBase
        {
            [Test]
            public void Assure_the_plus_operator_specifies_a_positive_number()
            {
                SetTemplateContent("${+number}");
                AddTemplateVariable("number", 3);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("3"));
            }

            [Test]
            public void Assure_the_minus_operator_specifies_a_negative_number()
            {
                SetTemplateContent("${-number}");
                AddTemplateVariable("number", 3);

                string output = ProcessTemplate();

                Assert.That(output, Is.EqualTo("-3"));
            }

            [Test]
            public void Assure_a_NonNumericalException_is_thrown_when_operator_is_applied_to_a_string()
            {
                SetTemplateContent("${-number}");
                AddTemplateVariable("number", "Hello");

                Assert.That(
                    () => ProcessTemplate(),
                    Throws.Exception.TypeOf<NonNumericalException>().
                        With.Message.ContainsSubstring("Expression number is not numerical."));
            }
        }
    }
}
// ReSharper enable InconsistentNaming